use std::collections::HashMap;
use chrono::{DateTime, Utc, Timelike, Datelike};

use crate::objects::{NewBar as Bar, Direction, Freq};
use crate::objects::signal::SimpleSignal;
use crate::utils::corr::single_linear;

/// 单K趋势因子辅助判断买卖点
pub fn bar_single_v230506(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let n = kwargs.get("n").unwrap_or(&5.0).to_owned() as usize;
    
    assert!(n <= 20, "n 的取值范围为 1~20，分层数量不宜太多");
    
    let mut signals = HashMap::new();
    
    if bars.len() < 100 + di {
        let signal = SimpleSignal::new(
            "单K趋势因子".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("单K趋势因子".to_string(), signal);
        return signals;
    }
    
    // 获取最近100根K线
    let start_idx = bars.len().saturating_sub(100 + di);
    let end_idx = bars.len().saturating_sub(di);
    let recent_bars = &bars[start_idx..end_idx];
    
    // 计算趋势因子
    let factors: Vec<f64> = recent_bars
        .iter()
        .map(|bar| (bar.close / bar.open - 1.0) / bar.vol)
        .collect();
    
    // 分层处理
    let min_factor = factors.iter().fold(f64::INFINITY, |a, &b| a.min(b));
    let max_factor = factors.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
    let range = max_factor - min_factor;
    
    let current_factor = factors[factors.len() - 1];
    let layer = if range > 0.0 {
        let normalized = (current_factor - min_factor) / range;
        ((normalized * n as f64) + 1.0) as usize
    } else {
        1
    };
    
    let signal = SimpleSignal::new(
        format!("第{}层", layer),
        true,
        Direction::Up,
        bars.last().unwrap().dt,
    );
    
    signals.insert(format!("第{}层", layer), signal);
    signals
}

/// 三K加速形态配合成交量变化
pub fn bar_triple_v230506(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    
    let mut signals = HashMap::new();
    
    if bars.len() < 7 {
        let signal = SimpleSignal::new(
            "三K加速".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("三K加速".to_string(), signal);
        return signals;
    }
    
    // 获取最近三根K线
    let b3 = &bars[bars.len() - 3 - di];
    let b2 = &bars[bars.len() - 2 - di];
    let b1 = &bars[bars.len() - 1 - di];
    
    let mut pattern = "其他";
    let mut volume_pattern = "量柱无序";
    
    // 判断三连涨
    if b1.close > b1.open && b2.close > b2.open && b3.close > b3.open {
        pattern = "三连涨";
        
        // 判断新高涨
        if b1.high > b2.high && b2.high > b3.high && b1.low > b2.low && b2.low > b3.low {
            pattern = "新高涨";
        }
    }
    // 判断三连跌
    else if b1.close < b1.open && b2.close < b2.open && b3.close < b3.open {
        pattern = "三连跌";
        
        // 判断新低跌
        if b1.high < b2.high && b2.high < b3.high && b1.low < b2.low && b2.low < b3.low {
            pattern = "新低跌";
        }
    }
    
    // 判断成交量变化
    if b1.vol > b2.vol && b2.vol > b3.vol {
        volume_pattern = "依次放量";
    } else if b1.vol < b2.vol && b2.vol < b3.vol {
        volume_pattern = "依次缩量";
    }
    
    let signal = SimpleSignal::new(
        format!("{}_{}", pattern, volume_pattern),
        pattern != "其他",
        if pattern.contains("涨") { Direction::Up } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert(format!("{}_{}", pattern, volume_pattern), signal);
    signals
}

/// K线振幅信号
pub fn bar_zdf_v221203(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let threshold = kwargs.get("threshold").unwrap_or(&0.05).to_owned();
    
    let mut signals = HashMap::new();
    
    if bars.len() < di + 1 {
        let signal = SimpleSignal::new(
            "K线振幅".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("K线振幅".to_string(), signal);
        return signals;
    }
    
    let current_bar = &bars[bars.len() - 1 - di];
    let amplitude = (current_bar.high - current_bar.low) / current_bar.low;
    
    let signal = SimpleSignal::new(
        "K线振幅".to_string(),
        amplitude > threshold,
        if amplitude > threshold { Direction::Up } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("K线振幅".to_string(), signal);
    signals
}

/// 成交量放大信号
pub fn bar_vol_grow_v221112(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let n = kwargs.get("n").unwrap_or(&5.0).to_owned() as usize;
    let threshold = kwargs.get("threshold").unwrap_or(&2.0).to_owned();
    
    let mut signals = HashMap::new();
    
    if bars.len() < n + di {
        let signal = SimpleSignal::new(
            "成交量放大".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("成交量放大".to_string(), signal);
        return signals;
    }
    
    let current_bar = &bars[bars.len() - 1 - di];
    let recent_bars = &bars[bars.len() - n - di..bars.len() - di];
    
    let avg_volume: f64 = recent_bars.iter().map(|bar| bar.vol).sum::<f64>() / n as f64;
    let volume_ratio = current_bar.vol / avg_volume;
    
    let signal = SimpleSignal::new(
        "成交量放大".to_string(),
        volume_ratio > threshold,
        if volume_ratio > threshold { Direction::Up } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("成交量放大".to_string(), signal);
    signals
}

/// 假突破信号
pub fn bar_fake_break_v230204(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let n = kwargs.get("n").unwrap_or(&20.0).to_owned() as usize;
    
    let mut signals = HashMap::new();
    
    if bars.len() < n + di + 1 {
        let signal = SimpleSignal::new(
            "假突破".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("假突破".to_string(), signal);
        return signals;
    }
    
    let current_bar = &bars[bars.len() - 1 - di];
    let recent_bars = &bars[bars.len() - n - di..bars.len() - di];
    
    let high = recent_bars.iter().map(|bar| bar.high).fold(f64::NEG_INFINITY, f64::max);
    let low = recent_bars.iter().map(|bar| bar.low).fold(f64::INFINITY, f64::min);
    
    let break_high = current_bar.high > high;
    let break_low = current_bar.low < low;
    
    let signal = SimpleSignal::new(
        "假突破".to_string(),
        break_high || break_low,
        if break_high { Direction::Up } else if break_low { Direction::Down } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("假突破".to_string(), signal);
    signals
}

/// 大阳线信号
pub fn bar_big_solid_v230215(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let threshold = kwargs.get("threshold").unwrap_or(&0.05).to_owned();
    
    let mut signals = HashMap::new();
    
    if bars.len() < di + 1 {
        let signal = SimpleSignal::new(
            "大阳线".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("大阳线".to_string(), signal);
        return signals;
    }
    
    let current_bar = &bars[bars.len() - 1 - di];
    let change_rate = (current_bar.close - current_bar.open) / current_bar.open;
    
    let is_big_solid = change_rate > threshold && current_bar.close > current_bar.open;
    
    let signal = SimpleSignal::new(
        "大阳线".to_string(),
        is_big_solid,
        if is_big_solid { Direction::Up } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("大阳线".to_string(), signal);
    signals
}

/// 反转信号
pub fn bar_reversal_v230227(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let n = kwargs.get("n").unwrap_or(&5.0).to_owned() as usize;
    
    let mut signals = HashMap::new();
    
    if bars.len() < n + di + 1 {
        let signal = SimpleSignal::new(
            "反转信号".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("反转信号".to_string(), signal);
        return signals;
    }
    
    let current_bar = &bars[bars.len() - 1 - di];
    let recent_bars = &bars[bars.len() - n - di..bars.len() - di];
    
    let highs: Vec<f64> = recent_bars.iter().map(|bar| bar.high).collect();
    let lows: Vec<f64> = recent_bars.iter().map(|bar| bar.low).collect();
    
    let max_high = highs.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
    let min_low = lows.iter().fold(f64::INFINITY, |a, &b| a.min(b));
    
    let break_high = current_bar.high > max_high;
    let break_low = current_bar.low < min_low;
    
    let signal = SimpleSignal::new(
        "反转信号".to_string(),
        break_high || break_low,
        if break_high { Direction::Up } else if break_low { Direction::Down } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("反转信号".to_string(), signal);
    signals
}

/// 时间信号
pub fn bar_time_v230327(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let hour = kwargs.get("hour").unwrap_or(&14.0).to_owned() as usize;
    let minute = kwargs.get("minute").unwrap_or(&30.0).to_owned() as usize;
    
    let mut signals = HashMap::new();
    
    if bars.len() < di + 1 {
        let signal = SimpleSignal::new(
            "时间信号".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("时间信号".to_string(), signal);
        return signals;
    }
    
    let current_bar = &bars[bars.len() - 1 - di];
    let current_hour = current_bar.dt.hour() as usize;
    let current_minute = current_bar.dt.minute() as usize;
    
    let is_target_time = current_hour == hour && current_minute >= minute;
    
    let signal = SimpleSignal::new(
        "时间信号".to_string(),
        is_target_time,
        if is_target_time { Direction::Up } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("时间信号".to_string(), signal);
    signals
}

/// 星期信号
pub fn bar_weekday_v230328(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let weekday = kwargs.get("weekday").unwrap_or(&5.0).to_owned() as usize; // 5表示周五
    
    let mut signals = HashMap::new();
    
    if bars.len() < di + 1 {
        let signal = SimpleSignal::new(
            "星期信号".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("星期信号".to_string(), signal);
        return signals;
    }
    
    let current_bar = &bars[bars.len() - 1 - di];
    let current_weekday = current_bar.dt.weekday().num_days_from_monday() as usize;
    
    let is_target_weekday = current_weekday == weekday;
    
    let signal = SimpleSignal::new(
        "星期信号".to_string(),
        is_target_weekday,
        if is_target_weekday { Direction::Up } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("星期信号".to_string(), signal);
    signals
}

/// 波动率信号
pub fn bar_volatility_v241013(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let n = kwargs.get("n").unwrap_or(&20.0).to_owned() as usize;
    let threshold = kwargs.get("threshold").unwrap_or(&0.02).to_owned();
    
    let mut signals = HashMap::new();
    
    if bars.len() < n + di {
        let signal = SimpleSignal::new(
            "波动率信号".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("波动率信号".to_string(), signal);
        return signals;
    }
    
    let recent_bars = &bars[bars.len() - n - di..bars.len() - di];
    let returns: Vec<f64> = recent_bars
        .windows(2)
        .map(|window| (window[1].close - window[0].close) / window[0].close)
        .collect();
    
    let mean_return = returns.iter().sum::<f64>() / returns.len() as f64;
    let variance = returns.iter().map(|r| (r - mean_return).powi(2)).sum::<f64>() / returns.len() as f64;
    let volatility = variance.sqrt();
    
    let signal = SimpleSignal::new(
        "波动率信号".to_string(),
        volatility > threshold,
        if volatility > threshold { Direction::Up } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("波动率信号".to_string(), signal);
    signals
}

/// 振幅震荡信号
pub fn bar_zfzd_v241013(bars: &[Bar], kwargs: &HashMap<String, f64>) -> HashMap<String, SimpleSignal> {
    let di = kwargs.get("di").unwrap_or(&1.0).to_owned() as usize;
    let n = kwargs.get("n").unwrap_or(&10.0).to_owned() as usize;
    let threshold = kwargs.get("threshold").unwrap_or(&0.03).to_owned();
    
    let mut signals = HashMap::new();
    
    if bars.len() < n + di {
        let signal = SimpleSignal::new(
            "振幅震荡".to_string(),
            false,
            Direction::Down,
            bars.last().unwrap().dt,
        );
        signals.insert("振幅震荡".to_string(), signal);
        return signals;
    }
    
    let recent_bars = &bars[bars.len() - n - di..bars.len() - di];
    let amplitudes: Vec<f64> = recent_bars
        .iter()
        .map(|bar| (bar.high - bar.low) / bar.low)
        .collect();
    
    let avg_amplitude = amplitudes.iter().sum::<f64>() / amplitudes.len() as f64;
    
    let signal = SimpleSignal::new(
        "振幅震荡".to_string(),
        avg_amplitude > threshold,
        if avg_amplitude > threshold { Direction::Up } else { Direction::Down },
        bars.last().unwrap().dt,
    );
    
    signals.insert("振幅震荡".to_string(), signal);
    signals
} 